/*
 * Copyright (c) 2010 Curtis Boyden.  All rights reserved. 
 * This software was developed by Curtis Boyden and is provided under the terms 
 * of the GNU Lesser General Public License, Version 2.1. You may not use 
 * this file except in compliance with the license. If you need a copy of the license, 
 * please go to http://www.gnu.org/licenses/lgpl-2.1.txt. The Original Code is ejMud
 * (Ewerp Java MUD).  The Initial Developer is Curtis Boyden.
 *
 * Software distributed under the GNU Lesser Public License is distributed on an "AS IS" 
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or  implied. Please refer to 
 * the license for the specific language governing your rights and limitations.
*/

package com.ewerp.mud.communications;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;

import com.ewerp.mud.characters.ISessionBoundCharacter;
import com.ewerp.mud.characters.Player;
import com.ewerp.mud.commands.ICommand;
import com.ewerp.mud.commands.ICommandEngine;
import com.ewerp.mud.commands.parsers.StringCommandParser;
import com.ewerp.mud.core.EwerpMud;
import com.ewerp.mud.core.plugin.EwerpPluginManager;
import com.ewerp.mud.core.session.ISession;
import com.ewerp.mud.entitycore.descriptions.meta.VisibleDescription;
import com.ewerp.mud.locations.rooms.IRoomManager;
import com.ewerp.mud.messages.IMessage;
import com.ewerp.mud.messages.SpeechMessage;
import com.ewerp.mud.security.permissions.AdminPermission;

public class SocketSession implements ISession, Runnable {
    
    protected enum SessionState {CONNECTED, LOGIN, PASSWORD, AUTHENTICATED};
    
    protected Socket socket = null;
    
    protected SessionState currentState = SessionState.CONNECTED;
    
    protected BufferedReader socketReader;
    protected BufferedWriter socketWriter;
    
    protected String login;
    protected String password;
    
    protected ISessionBoundCharacter user;
    
    public SocketSession(Socket socket) {
        this.socket = socket;
        (new Thread(this)).start();
    }

    @Override
    public void run() {
        try {
            ICommand command = null;
            socketReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            socketWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            
            while(!socket.isInputShutdown() && !socket.isOutputShutdown()) {
                switch(currentState) {
                    case AUTHENTICATED: {
                        command = StringCommandParser.parseString(user, socketReader.readLine());
                        if(command != null) {
                            ((ICommandEngine)EwerpPluginManager.getInstance().getPlugin(EwerpMud.defaultNamespace, ICommandEngine.class)).pushCommand(command);
                        }
                    }break;
                    case LOGIN: {
                        write("Username: ");
                        login = socketReader.readLine();
                        if((login != null) && (!login.equals(""))) {
                            currentState = SessionState.PASSWORD;
                        }
                    }break;
                    case PASSWORD: {
                        write("Password: ");
                        password = socketReader.readLine();
                        if((password != null) && (!password.equals(""))) {
                            // Authenticate credentials
                            user = new Player();
                            user.setName(login);
                            user.setSession(this);
                            user.getPermissions().add(new AdminPermission());
                            // Place character in starting room
                            user.setRoom(((IRoomManager)EwerpPluginManager.getInstance().getPlugin(EwerpMud.defaultNamespace, IRoomManager.class)).getStartRoom());
                            user.getRoom().addCharacter(user);
                            
                            currentState = SessionState.AUTHENTICATED;
                        }
                    }break;
                    case CONNECTED: {
                        write("Welcome to the mud. Please login to continue:");
                        newLine();
                        currentState = SessionState.LOGIN;
                    }break;
                }
            }
        } catch (NullPointerException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    protected String read() throws IOException {
        if(socketReader != null) {
            return socketReader.readLine();   
        }
        return null;
    }
    
    protected void write(String msg) throws IOException {
        if(socketWriter != null) {
            socketWriter.write(msg);
            socketWriter.flush();
        }
    }
    
    protected void newLine() throws IOException {
        if(socketWriter != null) {
            socketWriter.newLine();
            socketWriter.flush();
        }
    }

    @Override
    public void processMessage(IMessage message) {
        try {
            if(message instanceof SpeechMessage) {
                SpeechMessage sm = (SpeechMessage)message;
                String result = sm.getSource().getDescription(VisibleDescription.class).getText() + " says \"" + message.getText() + "\"";
                write(result);
            } else {
                write(message.getText());
            }
            newLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
